<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2020/12/1
 * Time: 14:20
 */

namespace app\index\controller;


use Protocol\Curl;
use think\Controller;

require_once ROOT . 'extend/F2FPay/f2fpay/model/builder/AlipayTradePayContentBuilder.php';
require_once ROOT . 'extend/F2FPay/f2fpay/model/builder/AlipayTradeRefundContentBuilder.php';
require_once ROOT . 'extend/F2FPay/f2fpay/service/AlipayTradeService.php';

class OrdersPay extends Controller
{
    /**
     * @var array
     * @content 微信支付配置信息
     */
    private $wx_config = [
        'appid' => 'wx281132202d144816', // APP APPID
        'app_id' => 'wx281132202d144816', // 公众号 APPID
        'miniapp_id' => 'wx281132202d144816', // 小程序 APPID
        'mch_id' => '1573261001',
        'key' => 'youpilive13236999488youpilive488',
        'notify_url' => 'http://coo.elianchefu.com/index/Payment/payBackWx',//支付回调地址
        'cert_client' => ROOT_PATH . '../extend/cert/apiclient_cert.pem', // optional, 退款，红包等情况时需要用到
        'cert_key' => ROOT_PATH . '../extend/cert/apiclient_key.pem',// optional, 退款，红包等情况时需要用到
        'log' => [ // optional
            'file' => '../runtime/payLogs//wechat.log',
            'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
            'type' => 'single', // optional, 可选 daily.
            'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
        ],
        'http' => [ // optional
            'timeout' => 5.0,
            'connect_timeout' => 5.0,
            // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
        ],
        // 'mode' => 'dev',
    ];

    /**
     * @param $body
     * @param $out_trade_no
     * @param $total_fee
     * @param $auth_code
     * @param null $device_info
     * @param null $attach
     * @return array
     * @content 微信付款码支付
     */
    function WxPay($body, $out_trade_no, $total_fee, $auth_code, $device_info = null, $attach = null)
    {

        if (is_null($body) or is_null($out_trade_no) or is_null($total_fee) or is_null($auth_code)) {
            return array('status' => false, 'msg' => '参数不能为空');
        } else {
            # 接口地址
            $_url = "https://api.mch.weixin.qq.com/pay/micropay";
            # 调用接口所需要的参数
            $data = array(
                'appid' => $this->wx_config['appid'],# 微信分配的公众账号ID（企业号corpid即为此appId     ->YES
                'mch_id' => $this->wx_config['mch_id'],# 微信支付分配的商户号                           ->YES
                'device_info' => $device_info,# 终端设备号(商户自定义，如门店编号)          ->NO
                'nonce_str' => $this->getNonceStr(),# 随机字符串，不长于32位                       ->YES
                'sign' => '',# 签名`                                            ->YES
                'body' => $body,# 商品简单描述，该字段须严格按照规范传递               ->YES
                'attach' => $attach,# 说明;附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据 ->NO
                'out_trade_no' => $out_trade_no,# 商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*且在同一个商户号下唯一 ->YES
                'total_fee' => floatval($total_fee) * 100, # 订单总金额，单位为分，只能为整数                 ->YES //floatval($total_fee)*100
                'fee_type' => 'CNY',# 货币类型(默认为人民币)                        ->NO
                'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],# 调用微信支付API的机器IP                 ->YES
                /*  'time_start' => '',# 订单生成时间                                  ->NO
                  'time_expire' => '',# 订单失效时间                                 ->NO*/
                'auth_code' => $auth_code,# 扫码支付授权码，设备读取用户微信中的条码或者二维码信息  ->YES
            );
            # 生成签名,并写回参数数组中
            $data['sign'] = $this->MakeSign($data);
            # 将数组转换成xml格式(去除空值)
            $_data = $this->ToXml(array_filter($data));
            #①、 使用post方式访问
            $send = new Curl();
            $_receipt = $send->post($_url, $_data, 'xml');
            # 将返回结果转换成数组格式
            $_receipt = $this->FromXml($_receipt);
            //②、 接口调用失败,请确认是否输入是否有误！
            if (!array_key_exists("return_code", $_receipt) || !array_key_exists("result_code", $_receipt)) {
                return array('status' => false, 'msg' => '接口调用失败,请确认是否输入是否有误！', 'receipt' => $_receipt);
            } else {
                // 接口调用成功，明确返回调用失败
                if ($_receipt["return_code"] == "SUCCESS" && $_receipt["result_code"] == "FAIL" && $_receipt["err_code"] != "USERPAYING" && $_receipt["err_code"] != "SYSTEMERROR") {
                    return array('status' => false, 'msg' => config('errCode.' . $_receipt['err_code']), 'receipt' => $_receipt);
                } else {
                    return array('status' => true);
                    /*// 获取该订单号(商户系统内部订单号)
                    $out_trade_no = $data['out_trade_no'];
                    // 微信的订单号，建议优先使用
                    $transaction_id = $_receipt['transaction_id'];
                    //③、确认支付是否成功
                    $queryTimes = 10;
                    while ($queryTimes > 0) {
                        $succResult = 0;
                        $queryResult = $this->OrderStatusQuery($out_trade_no, $transaction_id, $succResult);
                        $queryTimes--;
                        //如果需要等待1s后继续
                        if ($succResult == 2) {
                            sleep(2);
                            continue;
                        } else if ($succResult == 1) {//查询成功,返回订单查询结果
                            return array('status' => true, 'info' => $queryResult);
                            break;
                        } else {//订单交易失败
                            break;
                        }
                    }
                    # 支付失败,撤销订单
                    if (!$this->cancel($out_trade_no, $transaction_id)) {
                        return array('status' => false, 'msg' => "撤销单失败！");
                    }*/
                }
            }
        }
    }

    /**
     * @access public
     * @param $length int 随机字符串长度
     * @return string
     * @context 随机字符串
     */
    function getNonceStr($length = 32)
    {
        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = null;
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * @access public
     * @param $data array 传过来的所有数据
     * @return string
     * context 生成签名
     */
    function MakeSign($data)
    {
        # 初始化返回结果
        $_receipt = null;
        if (is_array($data) and !empty($data)) {
            # 对数组进行字典序排序
            ksort($data);
            #将参数格式化成url参数
            $buff = null;
            foreach ($data as $k => $v) {
                if ($k != "sign" and $v != "" and !is_array($v)) {
                    $buff .= $k . "=" . $v . "&";
                }
            }
            $buff = trim($buff, "&");
            # 在参数最后拼接上key
            $buff = $buff . "&key=" . $this->wx_config['key']; #  //注：key为商户平台设置的密钥key
            # 将参数进行MD5加密,全部转换成大写
            $_receipt = strtoupper(md5($buff));
        }
        return $_receipt;
    }

    /**
     * @access public
     * @param $data array 传过来的所有数据
     * @return string
     * context 转换成xml格式
     **/
    public function ToXml($data)
    {
        if (!is_array($data) || count($data) <= 0) {
            return false;
        }
        $xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * @access public
     * @param $xml array 传过来的所有数据
     * @return string
     * context 将xml转换成数组
     **/
    public function FromXml($xml)
    {
        if (!$xml) {
            return false;
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $_receipt = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $_receipt;
    }

    /**
     *
     * @access public
     * @param string $_out_trade_no 商户订单号
     * @param string $payType 支付方式
     * @param int $pay_price 支付金额
     * @context 查询订单状态情况
     * @return mixed 0 订单不成功，1表示订单成功，2表示继续等待
     */
    public function OrderStatusQuery($_out_trade_no, $payType, $pay_price,$mark=true)
    {
        if ($payType == 1) {
            # 微信支付
            $result = $this->orderStatus($_out_trade_no);
            if ($result["return_code"] == "SUCCESS" and $result["result_code"] == "SUCCESS") {
                //支付成功
                if ($result["trade_state"] == "SUCCESS") {
                    $payment = new Payment();
                    $payment->paySuccess($_out_trade_no, $payType, $pay_price);
                    return array('status' => true, 'is_continue' => 0, 'code' => 'SUCCESS', 'msg' => '支付成功');
                } //用户支付中
                else if ($result["trade_state"] == "USERPAYING") {
                    return array('status' => true, 'is_continue' => 1, 'code' => 'USERPAYING', 'msg' => '用户支付中');
                }else if ($result["trade_state"] == "REFUND") {
                    return array('status' => true, 'is_continue' => 0, 'code' => 'FAIL', 'msg' => '订单发生过退款');
                }else if ($result["trade_state"] == "PAYERROR") {
                    return array('status' => true, 'is_continue' => 0, 'code' => 'FAIL', 'msg' => '支付失败，请撤销订单');
                }
            }
            if(!$mark){
                dump($result);
            }
            //如果返回错误码为“此交易订单号不存在”则直接认定失败
            if ($result["err_code"] == "ORDERNOTEXIST") {
                # 撤销订单
                $this->cancel($_out_trade_no);
                return array('status' => false, 'is_continue' => 0, 'code' => $result->state, 'msg' => '支付失败');
            } else {
                //如果是系统错误，则后续继续
                return array('status' => true, 'is_continue' => 1, 'code' => 'FAIL', 'msg' => '查询失败');
            }
        } elseif ($payType == 2) {
            #支付宝支付
            //构造查询业务请求参数对象
            $queryContentBuilder = new \AlipayTradeQueryContentBuilder();
            $queryContentBuilder->setOutTradeNo($_out_trade_no);
            //初始化类对象，调用queryTradeResult方法获取查询应答
            $queryResponse = new \AlipayTradeService($this->ali_config);
            $queryResult = $queryResponse->queryTradeResult($queryContentBuilder);
            $_receipt = $queryResult->getResponse();
            //根据查询返回结果状态进行业务处理
            switch ($queryResult->getTradeStatus()) {
                case "SUCCESS":
                    if($mark) {
                        $payment = new Payment();
                        $payment->paySuccess($_out_trade_no, 2, $pay_price);
                    }
                    return array('status' => true, 'is_continue' => 0, 'msg' => '支付宝支付成功', 'receipt' => $_receipt);
                    break;
                case "FAILED":
                    return array('status' => false, 'is_continue' => 0, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                    break;
                case "UNKNOWN":
                    return array('status' => false, 'is_continue' => 1, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                    break;
                default:
                    return array('status' => false, 'is_continue' => 1, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                    break;
            }
        }
    }

    /**
     * @access public
     * @param string $transaction_id 微信的订单号，建议优先使用
     * @param string $out_trade_no 商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*@ ，且在同一个商户号下唯一。
     * @param int $timeOut
     * @return mixed 成功时返回，
     * @context 查询订单，WxPayOrderQuery中out_trade_no、transaction_id至少填一个
     */
    function orderStatus($out_trade_no = null, $transaction_id = null, $timeOut = 6)
    {
        # 返回结果初始化
        $_receipt = null;
        $_url = "https://api.mch.weixin.qq.com/pay/orderquery";
        # 判断微信订单号和商户系统内部订单号至少存在一个
        if (is_null($transaction_id) and is_null($out_trade_no)) {
            return false;
        } elseif (is_null($out_trade_no) and !is_null($transaction_id)) {
            # 设置接口所需参数,使用微信的订单号
            $data = array(
                'appid' => $this->wx_config['appid'],# 微信分配的公众账号ID（企业号corpid即为此appId     ->YES
                'mch_id' => $this->wx_config['mch_id'],# 微信支付分配的商户号
                'transaction_id' => $transaction_id, # 微信的订单号
                'nonce_str' => $this->getNonceStr(),# 随机字符串，不长于32位
                'sign' => '',# 签名
            );
        } elseif (!is_null($out_trade_no) and is_null($transaction_id)) {
            # 设置接口所需参数,使用系统内部订单号
            $data = array(
                'appid' => $this->wx_config['appid'],# 微信分配的公众账号ID（企业号corpid即为此appId     ->YES
                'mch_id' => $this->wx_config['mch_id'],# 微信支付分配的商户号
                'out_trade_no' => $out_trade_no, # 商户系统内部订单号
                'nonce_str' => $this->getNonceStr(),# 随机字符串，不长于32位
                'sign' => '',# 签名
            );
        } else {
            # 设置接口参数,都存在的情况下,优先使用微信的的订单号
            $data = array(
                'appid' => $this->wx_config['appid'],# 微信分配的公众账号ID（企业号corpid即为此appId     ->YES
                'mch_id' => $this->wx_config['mch_id'],# 微信支付分配的商户号
                'transaction_id' => $transaction_id, # 微信的订单号
                'nonce_str' => $this->getNonceStr(),# 随机字符串，不长于32位
                'sign' => '',# 签名
            );
        }
        # 生成签名,并写回参数数组中
        $data['sign'] = $this->MakeSign($data);
        # 将数组转换成xml格式
        $_data = $this->ToXml($data);
        # 使用post方式访问
        $send = new Curl();
        $_receipt = $send->post($_url, $_data, 'xml', false, $timeOut);
        # 将返回结果转换成数组格式
        $_receipt = $this->FromXml($_receipt);
        return $_receipt;
    }

    /**
     *
     * @access public
     * @param string $out_trade_no
     * @param string $transaction_id
     * @param int 调用深度 $depth
     * @return mixed
     * @context 撤销订单状态判断，如果失败会重复调用10次
     */
    public function cancel($out_trade_no = null, $transaction_id = null, $depth = 0)
    {
        if ($depth > 10) {
            return false;
        }
        $result = $this->reverse($out_trade_no, $transaction_id);
        //接口调用失败
        if ($result["return_code"] != "SUCCESS") {
            return false;
        }
        //如果结果为success且不需要重新调用撤销，则表示撤销成功
        if ($result["result_code"] != "SUCCESS" and $result["recall"] == "N") {
            return true;
        } else if ($result["recall"] == "Y") {
            return $this->cancel($out_trade_no, $transaction_id, ++$depth);
        }
        return false;
    }

    /**
     * @access public
     * @param string $transaction_id 微信的订单号，建议优先使用
     * @param string $out_trade_no 商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*@ ，且在同一个商户号下唯一。
     * @param int $timeOut
     * @return mixed 成功时返回，
     * @context 撤销订单，WxPayOrderQuery中out_trade_no、transaction_id至少填一个
     */
    function reverse($out_trade_no = null, $transaction_id = null, $timeOut = 6)
    {
        # 返回结果初始化
        $_receipt = null;
        $_url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
        # 判断微信订单号和商户系统内部订单号至少存在一个
        if (is_null($transaction_id) and is_null($out_trade_no)) {
            return false;
        } elseif (is_null($out_trade_no) and !is_null($transaction_id)) {
            # 设置接口所需参数,使用微信的订单号
            $data = array(
                'appid' => $this->wx_config['appid'],# 微信分配的公众账号ID（企业号corpid即为此appId     ->YES
                'mch_id' => $this->wx_config['mch_id'],# 微信支付分配的商户号
                'transaction_id' => $transaction_id, # 微信的订单号
                'nonce_str' => $this->getNonceStr(),# 随机字符串，不长于32位
                'sign' => '',# 签名
            );
        } elseif (!is_null($out_trade_no) and is_null($transaction_id)) {
            # 设置接口所需参数,使用系统内部订单号
            $data = array(
                'appid' => $this->wx_config['appid'],# 微信分配的公众账号ID（企业号corpid即为此appId     ->YES
                'mch_id' => $this->wx_config['mch_id'],# 微信支付分配的商户号
                'out_trade_no' => $out_trade_no, # 商户系统内部订单号
                'nonce_str' => $this->getNonceStr(),# 随机字符串，不长于32位
                'sign' => '',# 签名
            );
        } else {
            # 设置接口参数,都存在的情况下,优先使用微信的的订单号
            $data = array(
                'appid' => $this->wx_config['appid'],# 微信分配的公众账号ID（企业号corpid即为此appId     ->YES
                'mch_id' => $this->wx_config['mch_id'],# 微信支付分配的商户号
                'transaction_id' => $transaction_id, # 微信的订单号
                'nonce_str' => $this->getNonceStr(),# 随机字符串，不长于32位
                'sign' => '',# 签名
            );
        }
        # 生成签名,并写回参数数组中
        $data['sign'] = $this->MakeSign($data);
        # 将数组转换成xml格式
        $_data = $this->ToXml($data);
        # 使用post方式访问
        $send = new Curl();
        $_receipt = $send->post($_url, $_data, 'xml', true, $timeOut);
        # 将返回结果转换成数组格式
        $_receipt = $this->FromXml($_receipt);
        return $_receipt;
    }

    /**
     * @param $out_trade_no
     * @param $total_fee
     * @param $refund_fee
     * @param string $refund_desc
     * @param null $out_refund_no
     * @param int $fail_status
     * @return array
     * @content 微信支付订单退款
     */
    function wxRefund($out_trade_no, $total_fee, $refund_fee, $refund_desc = '订单退款', $out_refund_no = null, $fail_status = 1)
    {
        # 退款失败重新发起退款状态跟踪
//        $fail_status = 1;
        $url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        # 公众号id
        $appid = $this->wx_config['appid'];
        # 商户号
        $mch_id = $this->wx_config['mch_id'];
        # 随机字符串
        $nonce_str = $this->getNonceStr();
        # 商户退款单号
        if (empty($out_refund_no)) {
            $out_refund_no = $this->getsRefundOutNo();
        }
        $data = array(
            "appid" => $appid,
            "mch_id" => $mch_id,
            "nonce_str" => $nonce_str,
            "out_trade_no" => $out_trade_no,
            "out_refund_no" => $out_refund_no,
            "total_fee" => floatval($total_fee) * 100,
            "refund_fee" => floatval($refund_fee) * 100,
        );
        if (!empty($refund_desc)) {
            $data['refund_desc'] = $refund_desc;
        }
        # 签名
        $data['sign'] = $this->MakeSign($data);
        $_data = $this->ToXml(array_filter($data));
        $send = new Curl();
        $receipt = $this->FromXml($send->post($url, $_data, 'xml', true));
        if ($receipt['return_code'] == "SUCCESS") {
            # 提交申请成功
            if ($receipt['result_code'] == "SUCCESS") {
                # 退款成功
                return array('status' => true, 'msg' => '申请退款成功', 'refund_no' => $out_refund_no);
            } else {
                # 退款失败
                if ($receipt['err_code'] == "SYSTEMERROR" or $receipt['err_code'] == "BIZERR_NEED_RETRY") {
                    if ($fail_status <= 3) {
                        $fail_status++;
                        $this->wxRefund($out_trade_no, $total_fee, $refund_fee, $refund_desc, $out_refund_no, $fail_status);
                    }
                }
                return array('status' => false, 'msg' => config('errCode.' . $receipt['err_code']));
            }
        } else {
            return array('status' => false, 'msg' => $receipt['return_msg']);;
        }
    }

    /**
     * @access public
     * @return string 退款单号
     * @context 生成退款单号
     */
    function getsRefundOutNo()
    {

        $nonce_str = null;
        for ($i = 0; $i < 3; $i++) {
            # 随机小写字母
            $nonce_str_1 = chr(rand(97, 122));
            # 随机大写字母
            $nonce_str_2 = chr(rand(65, 90));
            # 随机数字
            $nonce_str_3 = rand(0, 9);
            $nonce_str .= $nonce_str_1;
            $nonce_str .= $nonce_str_2;
            $nonce_str .= $nonce_str_3;
        }
        $nonce_str = time() . $nonce_str;
        str_shuffle($nonce_str);
        return $nonce_str;
    }


    /*********************************************************************支付宝支付***************************************************************************/

    private $ali_config = array(
        //签名方式,默认为RSA2(RSA2048)
        'sign_type' => "RSA2",
        //应用ID
//        'app_id' => "2018111962219398",
        //支付宝公钥
//        'alipay_public_key' => "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0JKRz8titJWIM9Te2e52bNnvl/Ex9k4M6gFNW1XLo0c3UzKKNu3x8AynDXtRobUMwMMOME8RPVThrAGLFGMANkrPeV2xKW8MFd8+EOYalNPrBIX8k43y+TTlJcjoD0sS/fTalVW7dkJ0SqYYZELsnWf4APwtnw8w9WLGwsFOfJ6dBu65zXnZePmgIXZBb+AaYF610wBX76U6jd/QwdlTuteG8loGeUOF1DTKQ2ch07EUgXV+skiFXrDV+1ony05BEjc44ReM4sZZo4PyMWeEs5P3a0QfnWmY06pyxPoXqVpES/8GMKkJGLHS5d8BZsC+pi8mgezgE27iHr9FQC76nwIDAQAB",
        //商户私钥
//        'merchant_private_key' => "MIIEpQIBAAKCAQEAvRo+Z2yEbbOHV0LvFVqVhY6SpgoZ5jPHKs5HdlR72x1YJFPzdE1jLq8qbHiWGO4/IaGGQ/GVBggsqGC+ZaZrNek0FwZPcPBP39riJVQwiPLQnx9ZlGnrqrKWl0fKzQ3Lemf1HmbQg5xdwyNrrA2gpPBSBySYt/R8Mr6CE8PMHP6ce3I4aH9U8zDSXQPqTo5XEBYQ5Lt4jGZjCAf4jwSf2BOOM0MlQci7qpvhK/I+Y0nkAsiokOYRDrziCIo4RyNzFrzJfI+W8EfMVMtrBOPzEf2DTihMdOVWxlhTo9S/Uug7Imuo1yhAqrJc90bXQhHJGE+G63hWWwQKofU0OEuxUwIDAQABAoIBAFIrHiSYja6RTOTI69ROiRwAiI5nYzuZEhjyizDKowrh5FPcurO1kLxPVtLNTwNEOuBlLE9HoOZ/FNCRQQowVvOVApJippA/i6WMmal4vKI1SBtsZuNLZyDD+xV/F4skTF9C3sq4CDC3+DH7qSSYw04IMsxxxX5hWLo/94uZD48k/vo8mMcAPCPxgcGQsLSjM83z6MKST8Zt7qqZNyojNmNnue4qjTU12ZBi5z//FMk0tuKpySBOQ0CJ0ole26jFG5pM9PGlaLHAqhbgG3i3fCSrbWdE05hKQZH3c7AqU5zabWbIJ8XGudiOvFvHOivBgPjoADhu86g615jfMqd3PMkCgYEA9e3apQv3UcEbMIOYvAsV65R/mmbfbDyFssFV8jZa/d4Q9OdNgzg8yGyh6QRe7rVl0W2kjO5X/2eePuZTdJkLsi028Y1Nqs8Q12Z6oKqiuBcTk0LzWiJ7fE5CXemEX+XPKDa1ImWSgBWI+/IyyXCetcxY+U6b6iMM2+ot20OWGQ0CgYEAxNio9ivFX/6s7ofnqvT2zV7OJdBLaNYh9kY2BdlGaJb4L4rv5Oenqt9vupXAF0jC2tMzMc/QjUWpW1cPlkIlfIqxvz5Rn9UmRfWWJJfFlANJf2V9CUoio16AOKsqiXzGkGWyx8ysWMjv6JR+swpLXHy907OcyKPkO9YhOxqlm98CgYEA3lsTgH0EPbgClGe3lfXT+O+IPBtdUSibndbulZQNy1GYNUZZMBaN5o1KCzw3dU8v4x5mVEI/8B5I1wg7VsX17ECzV81x9slHqenvYAtIGnhK66/yBYH98pNzsCOt22MWXX6xYYtC3WobM+l1f+rCpQ9BNxCbKiRMwR3IHmLKeJUCgYEApU49Nd20NtUsbHP8/PgSeozvGZo+eZ+5jZOQsoCwPAzsByDqLJTNnRVeQpaXZfZYjGNoTqByRvEFNAt8r3aE/H2Mn0m6Sjs5lO6UU86QwaexBSc5RZ/YTtGBZBV591OtfH2rEVa0NSspLWvmqnwupVCsKShgta3McON1rKjIAokCgYEA4pFgVgKWorxHZaEpwO1aXHJod7TCpoxe7AVg+3yL4CwXxmNZ8kJyDA7jqVMe0iLzC2bxoQ0LZelRc9ZkGpe0T62A+WzhF4aS9rB6Us5t+L8FTkkJodOr1TSspCewy08OwSeIyowY9kgH5Khvjmyh7rsHBbbt47Uis6HZ4lDrmcU=",
        'app_id' => '2021002114641063',
        'merchant_private_key' => "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHDBAl+Fg3wIa741xCYZR79mMZCqwYCJ1HjwO4XV0AsXF4X3RcT/q+IhJymJmJ6kvta7ilClctQRWoSnyKUy5gd+foi0w3xZe7dfAswRzN6QdmcimUeOVDYEjG8/oS57yJrLSaGdROoQRqde8O+rV6Hzt1efL+UIM90KmJ99+Pa4I3Emv7atbyulvsSVjrN/AOuAL2WGOS7rTL2Q88J72sgUIOJ6bk9TFYyd5ydedQurDagv1DXTohCAJtFIQDnOZn/1QX+vRX4d8uePmhjNQ6v02U3jp6/z+wp68718WzMRuO/FMtbxLu93Bo8aH6WP5QkNal9zuP4RfxDALtacLvAgMBAAECggEAJSKwBJV/x+8IdBdoCA5yiGogdPSTxOweg9I/zG7GwjFYzS9p4yscycpLjMvBoYRv4/y79zalqxDAfKRg9eGs/lyAjNcoQiOAOn43b/IbcKMwOUHFVij0BQz6pvuvxUUs3La2/yUgggbybvZPwoitwPoAutskpaPZyHecmdv//p6ogW6fLqWyAkItNcDt/6De3A8TR4t209MfXvKT0NHFucYMPQF2rFl973bb9STPncpzrcU0fRW4tlpOuuLoOlMX03rC9XV3hsmXP9vtwM2ydB9hvJy+5Uot72Cd92hnXE/FLvPqbEzSw8f9NkAbAK0jjGtr1wkCnxNtqSLx3g8h6QKBgQD6FqTbz4/RtqRqvNzlyYhNQMstvCYSAPFQtOv1Ikk1m6yCScdm1NaJE3ds7Lu9Vu709+BFCz3usOljff2IdovinKH2OjahLQSHLdShC+qjQ8NPFsEzdGR9R3J2zJHNdqYpU9V+WqLgoPwSwgUDslDM4ffNdwYmFXiQSgv8U+T5awKBgQDLwI21v4H7P6QjZO+17kRSfZG6T1k7tKm4t26wC6P6v6l4tHLu2ejiahz1+LLXSCmgtD22ebGA/nNk5EsyodRbPMUElcvs54yBEm9XSsCg8Op+VfITEGFzDAviEWICcFwZY7ndrOVh91PjhRqctzS40lf1GE/KVR41RfbQNF7pjQKBgQDT+HVrShZgbioVvlaM/bBlqlGMRjkOcXYYLgEBGTpsEbK6C8bTRftA3BsRW+YUqaaIQ8D3RHwN4C0xgwxtqe0O+ivdA6JiIkIAQbxDdFJAZ6MXWfYPosu50+EVCHdcawCTbtc57aC4PDrruz98zprlzXG32PaBORmjUt+t0330WQKBgBsNFINlyp8N4v/j/cNcv+tnyno+4K0Bnmrsx6BN21aGLbzd0EiP29B7oB60ByJ37Tbt1yer3nouzik9+hHd1HDMj6e9L5bjYw8b4HZpcUus0KU3Se1oBlgc6FL6VdXXDxM730hkFQw9pwCVAmR+GlzTaGQc9zL4vAr8n/kiittdAoGBALqZbC4st0K2H865QLTk/ZHWa7zl3a+iuTOo8/HOugpURULfdRP4sY3QyJpwwq1MMLq84k9UP1HjssmNr9Jpr1MQyf3yacXNzqv2j0aDppJW+VOPRugZ58W/B2BRfowRhLAKDyNlPoUQS3seV6kZjHpwftMKyBsBqbAEU4iAUrQI",
        'alipay_public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAojSPnrmQl1GIIvNrRalo6QsnAYU3Wff3grKnHMoi0xZ6ftKMROB6tUY91AVa85CHld7MkrwZHlvDSjUrtzIfBnevpOSCUKIVgSEf4dO3WMbSlLDU7Pu5xz9gCM7WA6tbtvmszgwmk6piZDenSZcx08e4t1QIeBP5YxGjHM4lk8hPFgdSsP1frY7zVGw+fZxKl+QOcW6MtX89NqQOVe84IgSej4cWhTuSwBdKA5SoHLW2vuauvTwAF+qpETkUO4MzzPqYPTUe05Ap6NDbtVhctFerdbRudjfnYZe7Bgj4ukSz0Jc7eJ/BH/6jTZXYMQW7Ck7DwVShapp4pJoaLag11wIDAQAB',
        //编码格式
        'charset' => "UTF-8",
        //支付宝网关
        'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
        //异步通知地址,只有扫码支付预下单可用
        'notify_url' => "http://coo.elianchefu.com/index/Payment/payBackAli",
        //最大查询重试次数
        'MaxQueryRetry' => "10",
        //查询间隔
        'QueryDuration' => "3"
    );


    /**
     * @param $outTradeNo
     * @param $totalAmount
     * @param $authCode
     * @param string $subject
     * @return array
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     * @content 支付宝付款码支付
     */
    function AliPay($outTradeNo, $totalAmount, $authCode, $subject = 'E联车服联盟')
    {
        // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
//        $providerId = ""; //系统商pid,作为系统商返佣数据提取的依据
//        $extendParams = new ExtendParams();
//        $extendParams->setSysServiceProviderId($providerId);
//        $extendParamsArr = $extendParams->getExtendParams();

        // 支付超时，线下扫码交易定义为5分钟
        $timeExpress = "5m";
        // 创建请求builder，设置请求参数
        $barPayRequestBuilder = new \AlipayTradePayContentBuilder();
        $barPayRequestBuilder->setOutTradeNo($outTradeNo);
        $barPayRequestBuilder->setTotalAmount($totalAmount);
        $barPayRequestBuilder->setAuthCode($authCode);
        $barPayRequestBuilder->setTimeExpress($timeExpress);
        $barPayRequestBuilder->setSubject($subject);
        // 调用barPay方法获取当面付应答
        $barPay = new \AlipayTradeService($this->ali_config);
        $barPayResult = $barPay->barPay($barPayRequestBuilder);
        $_receipt = $barPayResult->getResponse();
        switch ($barPayResult->getTradeStatus()) {
            case "SUCCESS":
                $payment = new Payment();
                $payment->paySuccess($outTradeNo, 2, $totalAmount);
                return array('status' => true, 'is_continue' => 0, 'msg' => '支付宝支付成功', 'receipt' => $_receipt);
                break;
            case "FAILED":
                return array('status' => false, 'is_continue' => 0, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                break;
            case "UNKNOWN":
                return array('status' => false, 'is_continue' => 1, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                break;
            default:
                return array('status' => false, 'is_continue' => 1, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                break;
        }
    }

    /**
     * @param $out_trade_no
     * @param $refund_amount
     * @param null $out_request_no
     * @return array
     * @throws \Exception
     * @content 支付宝退款
     */
    function aliRefund($out_trade_no, $refund_amount, $out_request_no = null)
    {
        # 商户退款单号
        if (empty($out_request_no)) {
            $out_request_no = $this->getsRefundOutNo();
        }
        //创建退款请求builder,设置参数
        $refundRequestBuilder = new \AlipayTradeRefundContentBuilder();
        $refundRequestBuilder->setOutTradeNo($out_trade_no);
        $refundRequestBuilder->setRefundAmount($refund_amount);
        $refundRequestBuilder->setOutRequestNo($out_request_no);


        //初始化类对象,调用refund获取退款应答
        $refundResponse = new \AlipayTradeService($this->ali_config);
        $refundResult = $refundResponse->refund($refundRequestBuilder);
        $_receipt = $refundResult->getResponse();
        //根据交易状态进行处理
        switch ($refundResult->getTradeStatus()) {
            case "SUCCESS":
                return array('status' => true, 'msg' => '申请退款成功', 'receipt' => $_receipt, 'refund_no' => $out_request_no);
                break;
            case "FAILED":
                return array('status' => false, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                break;
            case "UNKNOWN":
                return array('status' => false, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                break;
            default:
                return array('status' => false, 'msg' => config('errCode.' . str_replace('ACQ.', '', $_receipt->sub_code)), 'receipt' => $_receipt);
                break;
        }
    }
}
